package com.ruoyi.system.service.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.ThridApiResponse;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.PCabinet;
import com.ruoyi.system.domain.PProduct;
import com.ruoyi.system.domain.PWareHouse;
import com.ruoyi.system.domain.vo.DeviceRegisterRequest;
import com.ruoyi.system.domain.vo.HardVersionRequest;
import com.ruoyi.system.mapper.PCabinetMapper;
import com.ruoyi.system.mapper.SequenceMapper;
import com.ruoyi.system.service.IPCabinetService;
import com.ruoyi.system.service.IPProductPropService;
import com.ruoyi.system.service.IPWareHouseService;
import com.ruoyi.system.service.ISequenceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 存储柜管理Service业务层处理
 *
 * @author ruoyi
 * @date 2024-12-31
 */
@Service
public class PCabinetServiceImpl extends ServiceImpl<PCabinetMapper, PCabinet> implements IPCabinetService
{
    private static final Logger logger = LoggerFactory.getLogger(PCabinetServiceImpl.class);


    @Autowired
    private IPProductPropService productPropService;
    @Autowired
    private IPWareHouseService wareHouseService;
    @Autowired
    private ISequenceService sequenceService;
    /**
     * 查询存储柜管理
     *
     * @param id 存储柜管理主键
     * @return 存储柜管理
     */
    @Override
    public PCabinet selectPCabinetById(Long id)
    {
        return baseMapper.selectPCabinetById(id);
    }

    /**
     * 查询存储柜管理列表
     *
     * @param pCabinet 存储柜管理
     * @return 存储柜管理
     */
    @Override
    public List<PCabinet> selectPCabinetList(PCabinet pCabinet)
    {
        List<PCabinet> pCabinets = baseMapper.selectPCabinetList(pCabinet);
        for (PCabinet cabinet : pCabinets) {
            List<PProduct> pl = cabinet.getProduct();
            for (PProduct product : pl) {
//                Date currentDate = new Date();
//                Date startTime = product.getStartTime();
//                Date endTime = product.getEndTime();
//                if (startTime!=null && endTime!=null) {
//                    if (currentDate.before(startTime)) {
//                        product.setUseStatus("未启用");
//                    } else if (currentDate.after(startTime) && currentDate.before(endTime)) {
//                        product.setUseStatus("启用中");
//                    } else if (currentDate.after(endTime)) {
//                        product.setUseStatus("停用");
//                    }
//                }
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.eq("product_id",product.getId());
                product.setProductPropList(productPropService.list(queryWrapper));
            }
        }
        return pCabinets;
    }

    /**
     * 新增存储柜管理
     *
     * @param pCabinet 存储柜管理
     * @return 结果
     */
    @Override
    public int insertPCabinet(PCabinet pCabinet)
    {

        return baseMapper.insertPCabinet(pCabinet);
    }

    /**
     * 修改存储柜管理
     *
     * @param pCabinet 存储柜管理
     * @return 结果
     */
    @Override
    public int updatePCabinet(PCabinet pCabinet)
    {
        pCabinet.setUpdateTime(DateUtils.getNowDate());
        return baseMapper.updatePCabinet(pCabinet);
    }

    /**
     * 批量删除存储柜管理
     *
     * @param ids 需要删除的存储柜管理主键
     * @return 结果
     */
    @Override
    public int deletePCabinetByIds(Long[] ids)
    {
        return baseMapper.deletePCabinetByIds(ids);
    }

    /**
     * 删除存储柜管理信息
     *
     * @param id 存储柜管理主键
     * @return 结果
     */
    @Override
    public int deletePCabinetById(Long id)
    {
        return baseMapper.deletePCabinetById(id);
    }



    public List<String> selectGroupByCode() {
        QueryWrapper<PCabinet> queryWrapper = Wrappers.query();
        queryWrapper.select("code").groupBy("code");
        return baseMapper.selectList(queryWrapper).stream()
                .map(PCabinet::getCode)
                .collect(Collectors.toList());
    }

    @Override
    public  Map<String,String> regisiter(DeviceRegisterRequest lockControlVo) {
        // 根据mac地址查询PCabinet
        QueryWrapper<PCabinet> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mac", lockControlVo.getMac());
        PCabinet existingCabinet = baseMapper.selectOne(queryWrapper);
        Map<String,String> result = new HashMap<>();
        if (existingCabinet != null) {
            // 存在则更新
            existingCabinet.setDeviceVersion(lockControlVo.getDeviceVersion()); // 假设用deviceVersion更新warehouseName
            existingCabinet.setCabinetIp(lockControlVo.getIp());
            baseMapper.updateById(existingCabinet);
            result.put("SID",existingCabinet.getCode());
            result.put("DevName",existingCabinet.getCabinetName());
        } else {
            PCabinet newCabinet = new PCabinet();
            newCabinet.setWareHouseId(1L);
            PWareHouse pWareHouse = wareHouseService.selectPWareHouseById(1L);
            newCabinet.setWarehouseName(pWareHouse.getName());
            newCabinet.setMac(lockControlVo.getMac());
            newCabinet.setCabinetIp(lockControlVo.getIp());
            newCabinet.setCabinetPort(8092);
            newCabinet.setDeviceVersion(lockControlVo.getDeviceVersion()); // 假设用deviceVersion设置warehouseName
            // 生成新的code
            String newCode = generateNextCode();
            newCabinet.setCode(newCode);
            newCabinet.setCabinetName(newCode+"柜"); // 设置默认名称
            baseMapper.insert(newCabinet);
            result.put("SID",newCode);
            result.put("DevName",newCode+"柜");
            logger.info("注册返回结果:{}",result);
        }
        return result;
    }


    private String generateNextCode() {
        Long nextVal = sequenceService.atomicIncrement("cabinet_code_seq");
        return String.format("%06d", nextVal);

    }


    private final ExecutorService executorService = Executors.newFixedThreadPool(10);
    /**
     * 给所有设备发送心跳
     */
    @Override
    public void sendHeartbeatToAllDevices() {
        List<PCabinet> pCabinets = baseMapper.selectList(new QueryWrapper<>());
        for (PCabinet cabinet : pCabinets) {
            CompletableFuture.runAsync(() -> {
                String apiUrl = "http://"+cabinet.getCabinetIp()+ "/device/heartbeat";
                logger.info("服务下发心跳url{}",apiUrl);
                try {
                    Map<String, Object> requestData = new HashMap<>();
                    requestData.put("SID", cabinet.getCode());

                    logger.info("向设备[{}]发送心跳请求", cabinet.getCode());
                    HttpResponse response = HttpRequest.post(apiUrl)
                            .body(JSONUtil.toJsonStr(requestData))
                            .contentType("application/json")
                            .timeout(5000) // 设置超时时间5秒
                            .execute();

                    if (response.isOk()) {
                        String body = response.body();
                        R<Map> resultObj = JSONUtil.toBean(body, R.class);
                        if (resultObj != null && resultObj.getCode() == 200) {
                            Map data = resultObj.getData();
                            if (data != null && "SUCCESS".equals(data.get("bizCode"))) {
                                logger.info("设备[{}]心跳成功", cabinet.getCode());
                            } else {
                                logger.error("设备[{}]心跳失败，业务码: {}, 消息: {}",
                                        cabinet.getCode(),
                                        data != null ? data.get("bizCode")  : "null",
                                        data != null ? data.get("bizMsg") : "null");
                            }
                        } else {
                            logger.error("设备[{}]心跳请求失败，响应码: {}", cabinet.getCode(), response != null ? resultObj.getCode() : "null");
                        }
                    }
                } catch (Exception e) {
                    logger.error("设备[{}]心跳请求异常: {}", cabinet.getCode(), e.getMessage(), e);
                }
            }, executorService);
        }
    }

    /**
     * 给所有设备升级硬件
     */
    @Override
    public Map<String, String> updateHardVersion(HardVersionRequest request) {
        List<PCabinet> pCabinets = baseMapper.selectList(new QueryWrapper<>());

        // 使用固定大小线程池控制并发
        ExecutorService executor = Executors.newFixedThreadPool(5);
        List<Future<?>> futures = new ArrayList<>();

        // 使用线程安全的Map记录失败信息 (柜子编号 -> 失败原因)
        Map<String, String> failedCabinets = new ConcurrentHashMap<>();
        for (PCabinet cabinet : pCabinets) {
            futures.add(executor.submit(() -> {
                String apiUrl = "http://" + cabinet.getCabinetIp()+":"+cabinet.getCabinetPort()  + "/device/update";
                try {
                    Map<String, Object> requestData = new HashMap<>();
                    requestData.put("SID", cabinet.getCode());
                    requestData.put("version", request.getHardVersion());
                    requestData.put("uploadUrl", request.getHardVersion());
                    requestData.put("updateType", "0");

                    logger.info("更新{}柜硬件版本,Url:{},参数:{}", cabinet.getCode(), apiUrl, requestData);

                    // 使用静态方法创建POST请求
                    HttpResponse response = HttpUtil.createPost(apiUrl)
                            .body(JSONUtil.toJsonStr(requestData))
                            .contentType("application/json")
                            .timeout(50000)
                            .execute();

                    if (response.isOk()) {
                        String body = response.body();
                        ThridApiResponse resultObj = JSONUtil.toBean(body, ThridApiResponse.class);
                        logger.info("下发密码响应结果：{},{},{}", resultObj.getBizCode(), resultObj.getBizMsg(), resultObj.getReceiverTime());
                        if (!"SUCCESS".equals(resultObj.getBizCode())) {
                            failedCabinets.put(cabinet.getCode(), resultObj.getBizMsg());
                            throw new ServiceException(resultObj.getBizMsg());
                        }
                    }
                } catch (Exception e) {
                    logger.error("设备[{}]更新失败: {}", cabinet.getCode(), e.getMessage(), e);
                    failedCabinets.put(cabinet.getCode(), e.getMessage());

                }
            }));
        }

        // 等待所有任务完成
        for (Future<?> future : futures) {
            try {
                future.get();
            } catch (Exception e) {
                logger.error("任务执行异常: {}", e.getMessage());
            }
        }

        executor.shutdown();
        return failedCabinets;
    }

    /**
     * 给单个设备升级硬件
     */
    @Override
    public void updateSingleHardVersion(HardVersionRequest request) {
        PCabinet cabinet=selectPCabinetById(request.getId());
        String apiUrl = "http://" + cabinet.getCabinetIp()+":"+cabinet.getCabinetPort()  + "/device/update";


        try {
            String uploadUrl=request.getHardVersion();
            String version="";
            int index = uploadUrl.indexOf("-"); // 查找 "-" 的位置
            if (index != -1 && index < uploadUrl.length() - 1) {
                version = uploadUrl.substring(index + 1); // 截取 "-" 之后的所有字符
            }
            Map<String, Object> requestData = new HashMap<>();
            requestData.put("SID", cabinet.getCode());
            requestData.put("version", version);
            requestData.put("uploadUrl",uploadUrl);
            requestData.put("updateType", "0");

            logger.info("更新{}柜硬件版本,Url:{},参数:{}", cabinet.getCode(), apiUrl, requestData);

            // 使用静态方法创建POST请求
            HttpResponse response = HttpUtil.createPost(apiUrl)
                    .body(JSONUtil.toJsonStr(requestData))
                    .contentType("application/json")
                    .timeout(50000)
                    .execute();

            if (response.isOk()) {
                String body = response.body();
                ThridApiResponse resultObj = JSONUtil.toBean(body, ThridApiResponse.class);
                logger.info("下发密码响应结果：{},{},{}", resultObj.getBizCode(), resultObj.getBizMsg(), resultObj.getReceiverTime());
                if (!"SUCCESS".equals(resultObj.getBizCode())) {
                    throw new ServiceException(resultObj.getBizMsg());
                }
            }
        } catch (Exception e) {
            logger.error("设备[{}]更新失败: {}", cabinet.getCode(), e.getMessage(), e);
            throw new ServiceException("更新失败");
        }
    }
}
